#include <QtGui>
#include <QtOpenGL>

#include <math.h>
#include <iostream>
#include <fstream>
#include "glwidget.h"
#include "AOProgressDialog.h"
#include "../geom/PolyModel.h"
#include "../geom/PolyObject.h"
#include "../dataengine/VibModelFileManager.h"

void GLWidget::showChooseOpenModelDialog()
{
    QString filename = showOpenModelDialog();
    if(filename !="")
    {
        QFileInfo file(filename);
        emit newTreeModelFileOpened(QString("- ")+file.baseName());
		update3DModel();
        updateGL();
    }
}

void GLWidget::showSaveFileDialog()
{
    QFileDialog::Options options;
    QString selectedFilter = "*.vib";
    QString fileName = QFileDialog::getSaveFileName(this,
            tr("Select tree model file to save"),
            QString("."),
            tr("ViBos Files(*.vib)"),
            &selectedFilter,
            options);
    if (fileName.isEmpty())
        return;

	geom::PolyObject pobject;

	vector<POVGeom::POVObject *>::const_iterator iter = trees.begin();
	vector<POVGeom::POVObject *>::const_iterator end = trees.end();
	for(;iter!=end;++iter)
	{
		auto_ptr<PolyModel> pm = (*iter)->convertToPolyModel();
		pobject.addModel(*(pm.release()));
	}
	// TODO add exception safety to this
	dataengine::VibModelFileManager modelSaver(fileName.toStdString());
	modelSaver.saveToFile(pobject);
}

void GLWidget::setOctreeResolution(int res)
{
	m_octreeRes = res;
}
void GLWidget::setAOQuality(int q)
{
	m_AOQuality = q;
}

void GLWidget::changeTreeColor(string partName, QColor color)
{
	if(selectedTree>=(int)trees.size())
		return;

	POVGeom::POVObject * tree = trees[selectedTree];
	if(!tree)
		return;
	int colori[3];
	color.getRgb(&colori[0],&colori[1],&colori[2]);
	float colorf[3];
	for(int i=0;i<3;i++)
		colorf[i] = colori[i]/255.0;
	tree->setPartColor(partName,colorf);

	m_renderer->generateVertexBufferObjects();
	updateGL();
}

void GLWidget::generateAOForSelectedModel()
{
	POVGeom::POVObject * tree ;
	try
	{
			tree = trees.at(selectedTree);
	}
	catch(...)
	{
		return;
	}

	int numMeshes = tree->numberOfMeshes();

	vector<int> pointsPerMesh;	
	for(int i=0;i<numMeshes;i++)
		pointsPerMesh.push_back(tree->getMesh(i).getNumberOfPoints());

	AOProgressDialog * progress = new AOProgressDialog(this,pointsPerMesh);

	BBox box = tree->getObjectBBox();
	Octree<Triangle> oct(box, m_octreeRes);
	aoThread * aot = new aoThread(tree, &oct, m_AOQuality, progress);
	aot->start();
	progress->exec();
	aot->wait();
	delete progress;
	m_renderer->generateVertexBufferObjects();
	updateGL();
}

void GLWidget::selectedFileChanged(int numFile)
{
    selectedTree = numFile; 
	printf("Emmiting clear\n");
    emit clearColorsList();

	if(selectedTree>=(int)trees.size())
		return;

	POVGeom::POVObject * tree;
	try
	{
		tree = trees.at(selectedTree);
	}
	catch(...)
	{
		return;
	}
	
	for(int i=0; i<tree->numberOfMeshes();i++)
	{
		const geom::PolyMesh & m = tree->getMesh(i);
		const Triplet<float> &meshcolor = m.baseColor();
		string name = m.name();
                emit addColorToList(name, QColor((int)(meshcolor[0]*255),(int)(meshcolor[1]*255),(int)(meshcolor[2]*255)));
	}
	update3DModel();
	updateGL();
}

void GLWidget::removeFile(int numFile)
{
    if(numFile<(int)trees.size())
    {
        delete(trees.at(numFile));
        trees.erase(trees.begin()+numFile);
    }
    update3DModel();
	updateGL();
}

QString GLWidget::showOpenModelDialog()
{
    QFileDialog::Options options;
    QString selectedFilter;
    QString fileName = QFileDialog::getOpenFileName(this,
            tr("Select tree model file"),
            QString("."),
            tr("POV files (*.pov;*.inc);;All Files"),
            &selectedFilter,
            options);
    if (fileName.isEmpty())
        return QString("");

    QFileInfo file(fileName);
    PolyModel * tree = readPOVFile(fileName.toStdString(),file.baseName().toStdString());

    if(tree == NULL)
    {
        QMessageBox::critical(this, tr("File error"),tr("Selected file is not a valid POV file."));
        return showOpenModelDialog();
    }
    else
    {
		POVGeom::POVObject * o = new POVGeom::POVObject(*tree);
		trees.push_back(o);
		delete tree;
		selectedFileChanged(trees.size()-1);
    }
    return fileName;
}

void GLWidget::showOpenFileDialog()
{
    QFileDialog::Options options;
	QString selectedFilter;
	auto_ptr<dataengine::VibModelFileManager> mod(new dataengine::VibModelFileManager(""));
	bool canLoad = false;
	do{
		QString fileName = QFileDialog::getOpenFileName(this,
				tr("Select ViBos Object file"),
				QString("."),
				tr("ViBos Object files (*.vib);;All Files"),
				&selectedFilter,
				options);
		if(fileName == "")
			return;

		mod.reset(new dataengine::VibModelFileManager(fileName.toStdString()));
		canLoad = mod->canLoadFile();
		if(!canLoad)
			QMessageBox::critical(this, tr("File error"),tr("Selected file is not a valid ViBos file."));
	}
	while(!canLoad);

	auto_ptr<geom::PolyObject> pobj(mod->loadFile());
	printf("A;adiendo tree\n");
	trees.erase(trees.begin(),trees.end());
	emit clearFilesList();
	for(int i=0;i<pobj->getNumberOfModels();i++)
	{
		POVGeom::POVObject * t = new POVGeom::POVObject(pobj->getModel(i));
		trees.push_back(t);
		emit newTreeModelFileOpened(QString(pobj->getModel(i).name().c_str()));

	}
	selectedFileChanged(0);
}

void GLWidget::setExposure(double exposure)
{
	m_mainShader->setUniform1f("exposure",exposure);
	updateGL();
}

void GLWidget::setGamma(double gamma)
{
	m_mainShader->setUniform1f("gamma",gamma);
	updateGL();
}

void GLWidget::setContrast(double contrast)
{
	m_mainShader->setUniform1f("contrast",contrast);
	updateGL();
}
void GLWidget::setBrightness(double brightness)
{
	skyBrightness=(float)brightness;
    m_sky.setSkyBrightness(brightness*500);
	updateGL();
}

void GLWidget::setBloomLevels(int bloomLevels)
{
	m_hblurShader->setUniform1i("bloomSamples",bloomLevels);
	m_vblurShader->setUniform1i("bloomSamples",bloomLevels);
	updateGL();
}

void GLWidget::setBloomDistance(double bloomDistance)
{
	m_hblurShader->setUniform1f("bloomDistance",bloomDistance);
	m_vblurShader->setUniform1f("bloomDistance",bloomDistance);
	updateGL();
}

void GLWidget::setBloomMean(double mean)
{
	m_hblurShader->setUniform1f("blurMean",mean);
	m_vblurShader->setUniform1f("blurMean",mean);
	updateGL();
}

void GLWidget::setBloomAmount(double amount)
{
	m_mainShader->setUniform1f("bloomAmount",amount);
	updateGL();
}

// SLOTS ------------->>

// << ------------!SLOTS

